package async

import (
	"fmt"
	"gitee.com/stevenchin/gin_study/async/completableFuture"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

/**
同步异步处理
TIPS：
	· goroutine 机制可以方便地实现异步处理；
	· 在启动新的goroutine时，不应该使用原始上下文，必须使用它的只读副本
*/

// Sync 同步处理
func Sync(ctx *gin.Context) {
	time.Sleep(3 * time.Second)
	ctx.String(http.StatusOK, "请求执行完毕："+ctx.Request.URL.Path)
}

// Async 异步处理
func Async(ctx *gin.Context) {
	// 需要搞一个副本
	context := ctx.Copy()
	// goroutine 异步处理
	go func() {
		time.Sleep(3 * time.Second)
		fmt.Println("协程异步执行内容完成：" + context.Request.URL.Path)
	}()
	sprintf := fmt.Sprintf("请求主线程执行完毕，观察控制台协程输出日志：" + context.Request.URL.Path)
	fmt.Println(sprintf)
	ctx.String(http.StatusOK, sprintf)
}

// FutureSupplyAsync 实现 CompletableFuture.supplyAsync 异步处理并获取返回值效果
func FutureSupplyAsync(ctx *gin.Context) {
	fmt.Println("FutureSupplyAsync start")
	// 异步执行
	future := completableFuture.GoCompletableFuture().SupplyAsync(func(parm any) (interface{}, error) {
		fmt.Println("FutureSupplyAsync SupplyAsync start")
		// 模拟一个耗时操作
		time.Sleep(2 * time.Second)
		fmt.Println("FutureSupplyAsync SupplyAsync end")
		return fmt.Sprintf("这是入参的值：%s", parm), nil
	}, "FutureSupplyAsync 测试")
	fmt.Println("FutureSupplyAsync running")
	// 获取结果
	if result, err := future.Get(); err != nil {
		fmt.Println("FutureSupplyAsync SupplyAsync error：" + err.Error())
	} else {
		sprintf := fmt.Sprintf("this result is：%s", result)
		fmt.Println("FutureSupplyAsync SupplyAsync get success. " + sprintf)
	}
	fmt.Println("FutureSupplyAsync end")
	ctx.String(http.StatusOK, "CompletableFuture SupplyAsync 效果执行完毕。观察控制台协程输出日志")
}

// FutureAllOf 实现 CompletableFuture.AllOf 异步处理并获取返回值效果
func FutureAllOf(ctx *gin.Context) {
	fmt.Println("CompletableFuture AllOf 效果执行开始")
	const total = 20
	array := [total]*completableFuture.CompletableFuture{}
	for i := 0; i < total; i++ {
		async := completableFuture.GoCompletableFuture().SupplyAsync(func(parm any) (interface{}, error) {
			// 模拟一个耗时操作
			var sprintf string
			toInt, _ := interfaceToInt(parm)
			i2 := toInt % 3
			if i2 == 0 {
				time.Sleep(1 * time.Second)
				sprintf = fmt.Sprintf("这是入参的值：%d 执行代码块为： %d", parm, i2)
			} else if i2 == 1 {
				time.Sleep(2 * time.Second)
				sprintf = fmt.Sprintf("这是入参的值：%d 执行代码块为： %d", parm, i2)
			} else {
				sprintf = fmt.Sprintf("这是入参的值：%d 执行代码块为： %d", parm, i2)
				time.Sleep(3 * time.Second)
			}
			fmt.Println(sprintf)
			return parm, nil
		}, i)
		array[i] = async
	}
	fmt.Println("CompletableFuture AllOf 效果执行开始中1")
	for _, future := range array {
		if result, err := future.Get(); err != nil {
			fmt.Println("FutureSupplyAsync AllOf error：" + err.Error())
		} else {
			fmt.Printf("FutureSupplyAsync AllOf get success：%d \n", result)
		}
	}
	s := "CompletableFuture AllOf 效果执行完毕。观察控制台协程输出日志，注意用时时长"
	fmt.Println(s)
	ctx.String(http.StatusOK, s)
}

// FutureSupplyThenApply 实现 CompletableFuture.ThenApply 效果
func FutureSupplyThenApply(ctx *gin.Context) {
	fmt.Println("FutureSupplyThenApply start")
	// 异步执行（但是要保存结果值）
	future := completableFuture.GoCompletableFuture(true).SupplyAsync(func(parm any) (interface{}, error) {
		fmt.Println("异步执行但是要保存结果值 start")
		// 模拟一个耗时操作
		time.Sleep(1 * time.Second)
		fmt.Println("异步执行但是要保存结果值 end")
		return fmt.Sprintf("入参的值：%s", parm), nil
	}, "异步执行但是要保存结果值")
	fmt.Println("FutureSupplyThenApply running1")
	apply1 := future.ThenApply(func(param any) (any, error) {
		fmt.Println("异步结果继续执行1 start")
		time.Sleep(1 * time.Second)
		fmt.Println("异步结果继续执行1 end")
		return fmt.Sprintf("这是被依赖的结果值1：%s", param), nil
	})
	fmt.Println("FutureSupplyThenApply running2")
	apply2 := future.ThenApply(func(param any) (any, error) {
		fmt.Println("异步结果继续执行2 start")
		time.Sleep(2 * time.Second)
		fmt.Println("异步结果继续执行2 end")
		return fmt.Sprintf("这是被依赖的结果值2：%s", param), nil
	})
	fmt.Println("FutureSupplyThenApply running3")
	apply3 := future.ThenApply(func(param any) (any, error) {
		fmt.Println("异步结果继续执行3 start")
		time.Sleep(3 * time.Second)
		fmt.Println("异步结果继续执行3 end")
		return fmt.Sprintf("这是被依赖的结果值3：%s", param), nil
	})
	fmt.Println("FutureSupplyThenApply running4")
	// 获取结果
	if result, err := apply1.Get(); err != nil {
		fmt.Println("异步结果继续执行1 error：" + err.Error())
	} else {
		sprintf := fmt.Sprintf("this is：%s", result)
		fmt.Println("异步结果继续执行1 success. " + sprintf)
	}
	if result, err := future.Get(); err != nil {
		fmt.Println("异步执行保存结果 error：" + err.Error())
	} else {
		sprintf := fmt.Sprintf("this is：%s", result)
		fmt.Println("异步执行保存结果 success. " + sprintf)
	}
	if result, err := apply2.Get(); err != nil {
		fmt.Println("异步结果继续执行2 error：" + err.Error())
	} else {
		sprintf := fmt.Sprintf("this is：%s", result)
		fmt.Println("异步结果继续执行2 success. " + sprintf)
	}
	if result, err := apply3.Get(); err != nil {
		fmt.Println("异步结果继续执行3 error：" + err.Error())
	} else {
		sprintf := fmt.Sprintf("this is：%s", result)
		fmt.Println("异步结果继续执行3 success. " + sprintf)
	}
	fmt.Println("FutureSupplyThenApply end")
	ctx.String(http.StatusOK, "CompletableFuture SupplyThenApply 效果执行完毕。观察控制台协程输出日志，注意用时时长")
}

// any 转 int
func interfaceToInt(value interface{}) (int, error) {
	switch v := value.(type) {
	case int:
		return v, nil
	case int8:
		return int(v), nil
	case int16:
		return int(v), nil
	case int32:
		return int(v), nil
	case int64:
		return int(v), nil
	case uint:
		return int(v), nil
	case uint8:
		return int(v), nil
	case uint16:
		return int(v), nil
	case uint32:
		return int(v), nil
	case uint64:
		return int(v), nil
	default:
		return 0, fmt.Errorf("Cannot convert %v to int", value)
	}
}
